// Package config provides configuration management for smart snapshotter
package config

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/smart-snapshotter/pkg/types"
	"gopkg.in/yaml.v3"
)

const (
	// DefaultConfigFile is the default configuration file name
	DefaultConfigFile = "config.yaml"

	// DefaultConfigDir is the default configuration directory
	DefaultConfigDir = "/etc/smart-snapshotter"
)

// Load loads configuration from file and environment variables
func Load() (*types.Config, error) {
	config := &types.Config{}

	// Load from default locations
	configPaths := []string{
		filepath.Join(DefaultConfigDir, DefaultConfigFile),
		filepath.Join(".", "config.yaml"),
		filepath.Join(".", "configs", "config.yaml"),
	}

	// Check if custom config path is provided via environment
	if configPath := os.Getenv("SMART_SNAPSHOTTER_CONFIG"); configPath != "" {
		configPaths = []string{configPath}
	}

	// Try to load from file
	configLoaded := false
	for _, path := range configPaths {
		if _, err := os.Stat(path); err == nil {
			if err := loadFromFile(path, config); err != nil {
				return nil, fmt.Errorf("failed to load config from %s: %w", path, err)
			}
			configLoaded = true
			break
		}
	}

	// Debug: Print loaded config
	if configLoaded {
		fmt.Printf("Loaded config: \n")
		fmt.Printf("  Storage.Type=%s, Storage.BasePath=%s\n", config.Storage.Type, config.Storage.BasePath)
		fmt.Printf("  Dedup.Enabled=%v, Dedup.Algorithm=%s\n", config.Dedup.Enabled, config.Dedup.Algorithm)
		fmt.Printf("  Cache.Type=%s, Cache.MaxSize=%d\n", config.Cache.Type, config.Cache.MaxSize)
		fmt.Printf("  Logging.Level=%s, Logging.Format=%s\n", config.Logging.Level, config.Logging.Format)
	}

	// Apply defaults if no config file found or if config is incomplete
	if !configLoaded || config.Storage.Type == "" || config.Storage.BasePath == "" {
		fmt.Printf("Applying defaults (configLoaded=%v, Type=%s, BasePath=%s)\n", configLoaded, config.Storage.Type, config.Storage.BasePath)
		applyDefaults(config)
	}

	// Override with environment variables
	applyEnvironmentOverrides(config)

	// Validate configuration
	if err := validate(config); err != nil {
		return nil, fmt.Errorf("invalid configuration: %w", err)
	}

	return config, nil
}

func loadFromFile(path string, config *types.Config) error {
	data, err := os.ReadFile(path)
	if err != nil {
		return err
	}

	return yaml.Unmarshal(data, config)
}

func applyDefaults(config *types.Config) {
	// Storage defaults
	config.Storage = types.StorageConfig{
		Type:        "overlay",
		BasePath:    "/var/lib/smart-snapshotter",
		MaxSize:     100 * 1024 * 1024 * 1024, // 100GB
		Compression: true,
		Encryption:  false,
	}

	// Dedup defaults
	config.Dedup = types.DedupConfig{
		Enabled:       true,
		Algorithm:     "both",
		BlockSize:     4096,
		MinFileSize:   1024,
		HashAlgorithm: "blake3",
	}

	// Cache defaults
	config.Cache = types.CacheConfig{
		Type:     "hybrid",
		MaxSize:  10 * 1024 * 1024 * 1024, // 10GB
		TTL:      3600,                    // 1 hour
		Strategy: "lru",
	}

	// Loader defaults
	config.Loader = types.LoaderConfig{
		PrefetchEnabled: true,
		PrefetchDepth:   2,
		MaxConcurrency:  10,
		Timeout:         300, // 5 minutes
	}

	// Metrics defaults
	config.Metrics = types.MetricsConfig{
		Enabled: true,
		Port:    29090,
		Path:    "/metrics",
	}

	// Logging defaults
	config.Logging = types.LoggingConfig{
		Level:    "info",
		Format:   "json",
		Output:   "stdout",
		FilePath: "/var/log/smart-snapshotter/snapshotter.log",
	}
}

func applyEnvironmentOverrides(config *types.Config) {
	// Storage overrides
	if val := os.Getenv("SMART_SNAPSHOTTER_STORAGE_TYPE"); val != "" {
		config.Storage.Type = val
	}
	if val := os.Getenv("SMART_SNAPSHOTTER_STORAGE_PATH"); val != "" {
		config.Storage.BasePath = val
	}

	// Dedup overrides
	if val := os.Getenv("SMART_SNAPSHOTTER_DEDUP_ENABLED"); val != "" {
		config.Dedup.Enabled = val == "true"
	}
	if val := os.Getenv("SMART_SNAPSHOTTER_DEDUP_ALGORITHM"); val != "" {
		config.Dedup.Algorithm = val
	}

	// Cache overrides
	if val := os.Getenv("SMART_SNAPSHOTTER_CACHE_ENABLED"); val != "" {
		config.Cache.Type = val
	}

	// Logging overrides
	if val := os.Getenv("SMART_SNAPSHOTTER_LOG_LEVEL"); val != "" {
		config.Logging.Level = val
	}
}

func validate(config *types.Config) error {
	// Validate storage configuration
	if config.Storage.Type == "" {
		return fmt.Errorf("storage type cannot be empty")
	}

	supportedStorageTypes := map[string]bool{
		"erofs":     true,
		"composefs": true,
		"overlay":   true,
	}

	if !supportedStorageTypes[config.Storage.Type] {
		return fmt.Errorf("unsupported storage type: %s", config.Storage.Type)
	}

	// Validate dedup configuration
	if config.Dedup.Enabled {
		supportedDedupAlgorithms := map[string]bool{
			"file":  true,
			"block": true,
			"both":  true,
		}

		if !supportedDedupAlgorithms[config.Dedup.Algorithm] {
			return fmt.Errorf("unsupported dedup algorithm: %s", config.Dedup.Algorithm)
		}

		supportedHashAlgorithms := map[string]bool{
			"sha256": true,
			"blake3": true,
		}

		if !supportedHashAlgorithms[config.Dedup.HashAlgorithm] {
			return fmt.Errorf("unsupported hash algorithm: %s", config.Dedup.HashAlgorithm)
		}
	}

	// Validate cache configuration
	supportedCacheTypes := map[string]bool{
		"memory": true,
		"disk":   true,
		"hybrid": true,
	}

	if !supportedCacheTypes[config.Cache.Type] {
		return fmt.Errorf("unsupported cache type: %s", config.Cache.Type)
	}

	supportedCacheStrategies := map[string]bool{
		"lru": true,
		"lfu": true,
	}

	if !supportedCacheStrategies[config.Cache.Strategy] {
		return fmt.Errorf("unsupported cache strategy: %s", config.Cache.Strategy)
	}

	// Validate logging configuration
	supportedLogLevels := map[string]bool{
		"debug": true,
		"info":  true,
		"warn":  true,
		"error": true,
	}

	if !supportedLogLevels[config.Logging.Level] {
		return fmt.Errorf("unsupported log level: %s", config.Logging.Level)
	}

	return nil
}